package edu.hawaii.myisern.commandline;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import edu.hawaii.myisern.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.organizations.jaxb.Organization;
import edu.hawaii.myisern.researchers.jaxb.Researcher;

/**
 * Provides query support for the MyISERN system.
 * 
 * @author Phuoc Le
 * @author Ka Yee Leung
 * @author Jared Sunouchi
 */
public class MyIsernQueries {

  private MyIsernXmlLoader myIsernXml;
  
  /** Holds the collaboration table columns. */
  private String[] collaborationTableColumns = 
      { "Name", "Collaborating-Organizations", "Collaboration-Types", "Years", 
      "Outcome-Types", "Description" };
  
  /** Holds the -researcher query for command line execution. */  
  private String researcherType = "-researcher";
  /** Holds the -collaboration query for command line execution. */  
  private String collaborationType = "-collaboration";
  /** Holds the -organization query for command line execution. */
  private String organizationType = "-organization";
  /** Holds the -year query for command line execution. */
  private String yearType = "-year";
  
  /**
   * Initializes this instance by loading the data from the XML files.
   * 
   * @param loader The MyIsernXmlLoader that loads and holds the data.
   * @throws Exception If problems occur.
   */
  public MyIsernQueries(MyIsernXmlLoader loader) throws Exception {
    this.myIsernXml = loader;
  }
  
  /**
   * Lists organizations based on their collaborations with other organizations.
   * 
   * @param argument The operator value: > or ==.
   * @param collaborationLevel The number of collaborations.
   * @return The string value of the list of organizations.
   */
  public String listOrganizations(String argument, int collaborationLevel) {
    List<Collaboration> collaborationsList = myIsernXml.getCollaborations().getCollaboration();
    List<Organization> organizationsList = myIsernXml.getOrganizations().getOrganization();
    StringBuffer returnValue = new StringBuffer();
    
    // determines the collaborationLevel of the given organization
    for (Organization organization : organizationsList) {
      int count = 0;
      // goes through all collaborations and create a list containing all collaboration names 
      for (Collaboration collaboration : collaborationsList) {
        String organizationNames = createListString(collaboration.getCollaboratingOrganizations()
            .getCollaboratingOrganization());
        if ((organizationNames.toLowerCase()).contains(organization.getName().toLowerCase())) {
          count++;
        }
      }
      
      // lists all organization satisfying the required collaboration level
      if (("-collaborationLevelEquals".equals(argument)) && (count == collaborationLevel)) {
        returnValue.append(organization.getName());
        String newLine = "\n";
        returnValue.append(newLine);
      }
      if (("-collaborationLevelGreaterThan".equals(argument)) && (count > collaborationLevel)) {
        returnValue.append(organization.getName());
        String newLine = "\n";
        returnValue.append(newLine);
      }
    }
    return returnValue.toString();
  }
  
  /**
   * Returns the description of the given researcher, collaboration or organization.
   * 
   * @param id ID of the researcher, collaboration or organization.
   * @param type Type of ID.
   * @return Description of the given ID.
   */
  public String generateDescription(String id, String type) {
      String name = id.replace('_', ' ');
      
      // returns the description of the given researcher
      if (researcherType.equalsIgnoreCase(type)) {
        List<Researcher> researcherList = myIsernXml.getResearchers().getResearcher();
        for (Researcher researcher : researcherList) {
          if (name.equalsIgnoreCase(researcher.getName())) {
            return researcher.getBioStatement().trim();            
          }          
        }
      }
      
      // returns the description of the given collaboration
      if (collaborationType.equalsIgnoreCase(type)) {
        List<Collaboration> collaborationList = myIsernXml.getCollaborations().getCollaboration();
        for (Collaboration collaboration : collaborationList) {
          if (name.equalsIgnoreCase(collaboration.getName())) {
            return collaboration.getDescription().trim();            
          }          
        }
      }

      // returns the description of the given organization
      if (organizationType.equalsIgnoreCase(type)) {
        List<Organization> organizationList = myIsernXml.getOrganizations().getOrganization();
        for (Organization organization : organizationList) {
          if (name.equalsIgnoreCase(organization.getName())) {
            return organization.getResearchDescription().trim();            
          }          
        }
      }    
    return null;
  }
  
  /**
   * Lists collaborations known for the given organization, year, or researcher.
   * 
   * @param idOrYear The unique ID of a researcher or organization, or the collaboration year.
   * @param type The type for the given type (organization, researcher, or year).
   * @return The JTable representation of the collaboration list.
   */
  public JTable listCollaborations(String idOrYear, String type) {
    Map<String, String> uniqueIds = myIsernXml.getUniqueIds();
    if (uniqueIds.containsKey(idOrYear)) {
      String name = idOrYear.replace('_', ' ');
      
      // obtains the organization that the researcher belonged to and
      // then determines the collaboration based on the organization
      if (researcherType.equalsIgnoreCase(type)) {
        List<Researcher> researcherList = myIsernXml.getResearchers().getResearcher();
        for (Researcher researcher : researcherList) {
          if (name.equalsIgnoreCase(researcher.getName())) {
            String organizationName = findResearcherOrganization(researcher.getOrganization());
            return createListCollaborationTable(organizationName, researcherType);
          }          
        }
      }
      // determines the collaboration(s) that the organization has
      if (organizationType.equalsIgnoreCase(type)) {
        List<Organization> organizationList = myIsernXml.getOrganizations().getOrganization();
        for (Organization organization : organizationList) {
          if (name.equalsIgnoreCase(organization.getName())) {
            return createListCollaborationTable(name, organizationType);            
          }          
        }
      }
      return null;
    }
    else {
      // calls the method to list collaborations based on the year
      if (yearType.equalsIgnoreCase(type)) {
        return createListCollaborationTable(idOrYear, yearType);
      }
      System.out.println("ID not found.");
      return null;
    }
  }
  
  /**
   * Returns the researcher's associated organization.
   * 
   * @param name Name of the researcher.
   * @return The researcher's associated organization.
   */
  public String findResearcherOrganization(String name) {
    List<Organization> organizationList = myIsernXml.getOrganizations().getOrganization();
    for (Organization organization : organizationList) {
      if (name.equalsIgnoreCase(organization.getName())) {
        return organization.getName();            
      }          
    }
    return null;
  }
  
  /**
   * Creates the table for the listCollaborations task.
   * 
   * @param nameOrYear The name of the organization or the year of the collaboration.
   * @param type The type of collaboration list table to be created.
   * @return The JTable representation of the collaborations that match.
   */
  public JTable createListCollaborationTable(String nameOrYear, String type) {
    List<Collaboration> collaborations = new ArrayList<Collaboration>();
    List<Collaboration> collaborationsList = myIsernXml.getCollaborations().getCollaboration();

    // creates a list for all collaboration years 
    // and determines the collaboration for the given year
    if (yearType.equalsIgnoreCase(type)) {
      for (Collaboration collaboration : collaborationsList) {
        List<BigInteger> yearsList = collaboration.getYears().getYear();
        for (BigInteger collaborationYear : yearsList) {
          int year = Integer.parseInt(nameOrYear);
          if (year == collaborationYear.intValue()) {
            collaborations.add(collaboration);
          }
        }
      }
      if (collaborations.isEmpty()) {
        System.out.println("Year not found.");
        return null;
      }
    }
    else {
      // obtains the collaboration of the organization by going through the list of collaborations
      for (Collaboration collaboration : collaborationsList) {
        String organizationNames = createListString(collaboration.getCollaboratingOrganizations()
            .getCollaboratingOrganization());
        if ((organizationNames.toLowerCase()).contains(nameOrYear.toLowerCase())) {
          collaborations.add(collaboration);
        }
      }
    }

    // generates a JTable for the collaborations found
    String[][] data = new String[collaborations.size()][collaborationTableColumns.length];
    int count = 0;
    for (Collaboration collaboration : collaborations) {
      data[count][0] = collaboration.getName();
      data[count][1] = createListString(collaboration.getCollaboratingOrganizations()
          .getCollaboratingOrganization());
      data[count][2] = createListString(collaboration.getCollaborationTypes()
          .getCollaborationType());

      // gets the list of collaboration years and turns it into a string
      List<BigInteger> yearsList = collaboration.getYears().getYear();
      int listSize = yearsList.size();
      int listCount = 1;
      StringBuffer yearNames = new StringBuffer();
      for (BigInteger year : yearsList) {
        yearNames.append(year.toString());
        if (listCount < listSize) {
          String separator = ", ";
          yearNames.append(separator);
        }
        listCount++;
      }
      data[count][3] = yearNames.toString();
      
      data[count][4] = createListString(collaboration.getOutcomeTypes().getOutcomeType());
      data[count][5] = collaboration.getDescription();
      count++;
    }
    
    // creates the JTable
    final JTable table = new JTable(data, collaborationTableColumns);

    return table;
  }
  
  /**
   * Generates a string representation of a list.
   * 
   * @param listElements The list of elements that will be turned into a string.
   * @return The string representation of the list.
   */
  public String createListString(List<String> listElements) {
    int listSize = listElements.size();
    int listCount = 1;
    StringBuffer listString = new StringBuffer();
    for (String element : listElements) {
      if (listCount < listSize) {
        element += ", ";
      }
      listString.append(element);
      listCount++;
    }
    
    return listString.toString();
  }
  
  /**
   * Generates the panel for the given table.
   * 
   * @param table The table that will turned into the panel.
   * @return The panel representation of the table.
   */
  public JPanel createJPanel(JTable table) {
    table.setPreferredScrollableViewportSize(new Dimension(1000, 40));
    table.setFillsViewportHeight(true);
    JScrollPane scrollPane = new JScrollPane(table);
    JPanel viewTable = new JPanel(new GridLayout(1, 0));
    viewTable.add(scrollPane);
    
    return viewTable;
  }
}
